﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using TeacherLeftHand.DataAccess;
using TeacherLeftHand.Messages;
using TeacherLeftHand.Model;
using TeacherLeftHand.Util;
using MessageBox = System.Windows.MessageBox;

namespace TeacherLeftHand.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public sealed class TeachingMethodManageViewModel : ViewModelBase
    {
        #region constructor
        public TeachingMethodManageViewModel()
        {
            LoadAll();
            // register mesage
            Messenger.Default.Register<UpdateTMMessage>(this, UpdateTMList);
        }
        #endregion

        #region properties
        private readonly TeachingMethodAccessor _tmAccessor = new TeachingMethodAccessor();
        private TeachingMethod _selectedTeachingMethod = new TeachingMethod();
        private TMSearchCondition _searchCondition = new TMSearchCondition();


        public const string SelectedTeachingMethodPropertyName = "SelectedTeachingMethod";
        public TeachingMethod SelectedTeachingMethod
        {
            get
            {
                return _selectedTeachingMethod;
            }
            set
            {
                if (_selectedTeachingMethod != value)
                {
                    _selectedTeachingMethod = value;
                    RaisePropertyChanged(SelectedTeachingMethodPropertyName);
                    RaisePropertyChanged(HasTMsPropertyName);
                    Messenger.Default.Send(value, SelectedTeachingMethodPropertyName);
                }
            }
        }


        /// <summary>
        /// The <see cref="IsLoading" /> property's name.
        /// </summary>
        public const string IsLoadingPropertyName = "IsLoading";

        private bool _isLoading;

        /// <summary>
        /// Gets the IsLoading property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }

            set
            {
                if (_isLoading == value)
                {
                    return;
                }

                _isLoading = value;
                // Update bindings, no broadcast
                RaisePropertyChanged(IsLoadingPropertyName);
            }
        }
        /// <summary>
        /// The <see cref="ClassLevelList" /> property's name.
        /// </summary>
        public const string ClassLevelListPropertyName = "ClassLevelList";

        private readonly ObservableCollection<int> _classLevelList = DataHelper.ClassLevelList;

        /// <summary>
        /// Gets the ClassLevelList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<int> ClassLevelList
        {
            get
            {
                return _classLevelList;
            }
        }

        /// <summary>
        /// The <see cref="SubjectList" /> property's name.
        /// </summary>
        public const string SubjectListPropertyName = "SubjectList";

        /// <summary>
        /// Gets the SubjectList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<string> SubjectList
        {
            get
            {
                var list = (new KnowledgeItemAccessor()).GetSubjectList();
                list.Insert(0, "");
                return list;
            }

        }
        public const string HasTMsPropertyName = "HasTMs";
        /// <summary>
        /// Gets the HasKIs property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool HasTMs
        {
            get
            {
                if (SelectedTeachingMethod == null) return false;
                if (SelectedTeachingMethod.ID == -1) return false;
                return TMList.Count > 0;
            }
        }

        private ObservableCollection<TeachingMethod> _tmList;
        /// <summary>
        /// list of search result
        /// </summary>
        public ObservableCollection<TeachingMethod> TMList
        {
            get
            {
                if (_tmList == null)
                {
                    LoadAll();
                }
                return _tmList;
            }
            set
            {
                _tmList = value;
                RefreshPaging();
                RaisePropertyChanged("TMList");
            }
        }

        private ICommand _createCommand;
        public ICommand CreateCommand
        {
            get
            {
                if (_createCommand == null)
                {
                    _createCommand = new RelayCommand(Create);
                }
                return _createCommand;
            }

        }


        private ICommand _deleteCommand;
        /// <summary>
        /// bind to delete button or context menu
        /// </summary>
        public ICommand DeleteCommand
        {
            get
            {
                if (_deleteCommand == null)
                {
                    _deleteCommand = new RelayCommand(() =>
                    {
                        var result = MessageBox.Show(DataHelper.DeleteConfirmationMessage,
                                        DataHelper.DeleteConfirmationCaption,
                                        MessageBoxButton.OKCancel, MessageBoxImage.Warning);
                        if (result == MessageBoxResult.Cancel) return;
                        if (Delete(SelectedTeachingMethod))
                        {
                            // broadcast message to all who register
                            var msg = new UpdateTMMessage
                            {
                                Action = UpdateAction.Delete,
                                TeachingMethod = SelectedTeachingMethod
                            };
                            Messenger.Default.Send(msg);
                        }
                    });

                }
                return _deleteCommand;
            }
        }

        public TMSearchCondition SearchCondition
        {
            get
            {
                return _searchCondition;
            }
            set
            {
                if (_searchCondition != value)
                {
                    _searchCondition = value;
                    RaisePropertyChanged("SearchCondition");
                }
            }
        }

        private ICommand _searchCommand;
        public ICommand SearchCommand
        {
            get
            {
                if (_searchCommand == null)
                {
                    _searchCommand = new RelayCommand(() =>
                    {
                        if (SearchCondition.AdvancedSearchMode)
                            TMList = AdvanceSearch(SearchCondition);
                        else
                            TMList = Search(SearchCondition);
                        if (TMList.Count == 0)
                        {
                            LoadAll();
                        }

                        SelectedTeachingMethod = TMList.Count > 0 ? TMList.First() : null;
                        RefreshPaging();
                        RaisePropertyChanged("TMList");
                    });
                }
                return _searchCommand;
            }
        }

        #endregion

        #region methods

        /// <summary>
        /// delete a selected tm from the database
        /// </summary>
        public bool Delete(TeachingMethod item)
        {
            return _tmAccessor.Delete(item);
        }

        /// <summary>
        /// search tm based on provided condition
        /// </summary>
        private ObservableCollection<TeachingMethod> Search(TMSearchCondition searchCondition)
        {
            return _tmAccessor.Search(searchCondition);
        }

        private ObservableCollection<TeachingMethod> AdvanceSearch(TMSearchCondition searchCondition)
        {
            return _tmAccessor.AdvanceSearch(searchCondition);
        }
        private void LoadAll()
        {
            var result = new ObservableCollection<TeachingMethod>();
            var worker = new BackgroundWorker();
            worker.DoWork += (s, e) =>
            {
                result = _tmAccessor.GetAll();
            };
            worker.RunWorkerCompleted += (s, e) =>
                                             {
                                                 _tmList = result;
                                                 IsLoading = false;
                                                 RefreshPaging();
                                                 RaisePropertyChanged("TMList");
                                             };
            IsLoading = true;
            worker.RunWorkerAsync();

        }

        private void UpdateTMList(UpdateTMMessage msg)
        {
            switch (msg.Action)
            {
                case UpdateAction.Add:
                    TMList.Add(msg.TeachingMethod);
                    RefreshPaging();
                    RaisePropertyChanged("TMList");
                    RaisePropertyChanged(HasTMsPropertyName);
                    SelectedTeachingMethod = TMList[0];

                    break;
                case UpdateAction.Update:
                    if (TMList.Count <= 0) break;
                    var index = TMList.IndexOf(TMList.Where(x => x.ID == msg.TeachingMethod.ID).Select(x => x).First());
                    if (index >= 0)
                    {
                        TMList.RemoveAt(index);
                        TMList.Insert(index, new TeachingMethod(msg.TeachingMethod));
                        //set selected teaching method
                        RefreshPaging();
                        RaisePropertyChanged("TMList");
                        SelectedTeachingMethod = TMList[index];
                    }

                    break;
                case UpdateAction.Delete:
                    if (TMList.Count <= 0) break;
                    index = TMList.IndexOf(TMList.Where(x => x.ID == msg.TeachingMethod.ID).Select(x => x).First());
                    if (index >= 0)
                    {
                        TMList.RemoveAt(index);
                        RefreshPaging();
                        RaisePropertyChanged("TMList");
                        SelectedTeachingMethod = TMList.Count > 0 ? TMList.Last() : new TeachingMethod();
                    }
                    break;
                default:
                    throw new NotSupportedException("Unknown Update Action");
            }

        }

        private void Create()
        {
            SelectedTeachingMethod = null;
            Messenger.Default.Send(new TeachingMethodViewMessage());

        }

        #endregion

        #region PAGING ***********************************************************************************
        private int _currentPage = 1;
        private int _totalPages = 1;
        const int RECORDS_PER_PAGE = 15;
        private enum PagingMode { Next = 2, Previous = 3, First = 1, Last = 4 };
        private ObservableCollection<TeachingMethod> _pagedTMList = new ObservableCollection<TeachingMethod>();
        public ObservableCollection<TeachingMethod> PagedTMList
        {
            get
            {
                return _pagedTMList;
            }
            set
            {
                _pagedTMList = value;
                RaisePropertyChanged("PagedTMList");
            }
        }

        private ICommand _firstPage;
        public ICommand FirstPageCommand
        {
            get
            {
                if (_firstPage == null)
                {
                    _firstPage = new RelayCommand(() => CustomPaging((int)PagingMode.First), () => _currentPage > 1);
                }
                return _firstPage;
            }

        }

        private ICommand _prevPage;
        public ICommand PrevPageCommand
        {
            get
            {
                if (_prevPage == null)
                {
                    _prevPage = new RelayCommand(() => CustomPaging((int)PagingMode.Previous), () => _currentPage > 1);
                }
                return _prevPage;
            }
        }

        private ICommand _nextPage;
        public ICommand NextPageCommand
        {
            get
            {
                if (_nextPage == null)
                {
                    _nextPage = new RelayCommand(() => CustomPaging((int)PagingMode.Next), () => _currentPage < _totalPages);
                }
                return _nextPage;
            }
        }

        private ICommand _lastPage;
        public ICommand LastPageCommand
        {
            get
            {
                if (_lastPage == null)
                {
                    _lastPage = new RelayCommand(() => CustomPaging((int)PagingMode.Last), () => _currentPage < _totalPages);
                }
                return _lastPage;
            }
        }

        private ICommand _pageChanged;
        public ICommand PageChanged
        {
            get
            {
                if (_pageChanged == null)
                {
                    _pageChanged = new RelayCommand<string>(text =>
                    {
                        try
                        {
                            var temp = int.Parse(text);
                            if (temp > 0 && temp <= TotalPages)
                            {
                                CurrentPage = temp;
                                RefreshPaging();
                            }
                            else
                            {
                                CurrentPage = _currentPage;
                            }
                        }
                        catch (FormatException)
                        {
                            CurrentPage = _currentPage;
                        }
                    });
                }
                return _pageChanged;
            }
        }

        private void CustomPaging(int mode)
        {

            switch (mode)
            {
                case (int)PagingMode.Next:
                    //if (_kiList.Count > (_currentPage * RECORDS_PER_PAGE))
                    //{
                    //    _pagedKIList.Clear();

                    //    if (_kiList.Count >= ((_currentPage * RECORDS_PER_PAGE) + RECORDS_PER_PAGE))
                    //    {
                    //        for (int i = _currentPage * RECORDS_PER_PAGE; i < ((_currentPage * RECORDS_PER_PAGE) + RECORDS_PER_PAGE); i++)
                    //        {
                    //            _pagedKIList.Add(KIList[i]);
                    //        }
                    //    }
                    //    else
                    //    {
                    //        for (int i = _currentPage * RECORDS_PER_PAGE; i < KIList.Count; i++)
                    //        {
                    //            _pagedKIList.Add(KIList[i]);
                    //        }
                    //    }

                    //    CurrentPage++;
                    //}
                    if (CurrentPage < TotalPages)
                    {
                        CurrentPage++;
                    }
                    break;
                case (int)PagingMode.Previous:
                    //if (_currentPage > 1)
                    //{
                    //    _pagedKIList.Clear();
                    //    CurrentPage--;
                    //    for (int i = ((_currentPage * RECORDS_PER_PAGE) - RECORDS_PER_PAGE); i < (_currentPage * RECORDS_PER_PAGE); i++)
                    //    {
                    //        _pagedKIList.Add(_kiList[i]);
                    //    }

                    //}
                    if (CurrentPage > 1)
                    {
                        CurrentPage--;
                    }
                    break;
                case (int)PagingMode.First:
                    //CurrentPage = 2;
                    //CustomPaging((int)PagingMode.Previous);
                    if (TotalPages > 0)
                    {
                        CurrentPage = 1;
                    }
                    break;
                case (int)PagingMode.Last:
                    //CurrentPage = _totalPages - 1;
                    //CustomPaging((int)PagingMode.Next);
                    if (TotalPages > 0)
                    {
                        CurrentPage = TotalPages;
                    }
                    break;
            }
            RefreshPaging();
        }

        private void RefreshPaging()
        {

            try
            {
                _pagedTMList.Clear();

                if (TMList.Count > 0)
                {
                    TotalPages = (_tmList.Count % RECORDS_PER_PAGE == 0) ? _tmList.Count / RECORDS_PER_PAGE : _tmList.Count / RECORDS_PER_PAGE + 1;
                    CurrentPage = _currentPage < _totalPages ? _currentPage : _totalPages;
                    if (_currentPage == 0)
                    {
                        CurrentPage = 1;
                    }
                    if (_tmList.Count >= _currentPage * RECORDS_PER_PAGE)
                    {
                        for (int i = (_currentPage - 1) * RECORDS_PER_PAGE; i < _currentPage * RECORDS_PER_PAGE; i++)
                        {
                            _pagedTMList.Add(_tmList[i]);
                        }
                    }
                    else
                    {
                        for (int i = (_currentPage - 1) * RECORDS_PER_PAGE; i < _tmList.Count; i++)
                        {
                            _pagedTMList.Add(_tmList[i]);
                        }
                    }
                }
                else
                {
                    TotalPages = 0;
                    CurrentPage = 0;
                }
                //try
                //{
                //if (_kiList.Count > 0)
                //{
                //    if(_currentPage>0)
                //    {
                //        _currentPage--;
                //    }

                //    CustomPaging((int)PagingMode.Next);
                //}
                //else
                //{
                //    CurrentPage = 0;
                //}
                //else
                //{
                //    MessageBox.Show("No Records Exists for the selected category");
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public int CurrentPage
        {
            get
            {
                return _currentPage;
            }
            set
            {
                _currentPage = value;
                RaisePropertyChanged("CurrentPage");
            }
        }

        public int TotalPages
        {
            get
            {
                return _totalPages;
            }
            set
            {
                _totalPages = value;
                RaisePropertyChanged("TotalPages");
            }
        }
        #endregion paging
    }

}